library sqliteasy_sqflite;
import 'dart:async';

import 'package:sqliteasy_core/enums/null_value_strategy.dart';
import 'package:sqliteasy_core/sqliteasy_core.dart' hide Database;
import 'package:sqflite/sqflite.dart';

class SqfliteDatabaseOpenHelper extends DatabaseOpenAdapter {
  @override
  Future<SupportSQLiteDatabase> onOpen(DatabaseConfiguration configuration, int version, VersionUpdater onUpgrade, VersionUpdater onDowngrade) async {
    final db = SqfliteSupportDatabase(await openDatabase(configuration.name, version: version, onUpgrade: (Database db, int oldVersion, int newVersion) async {
      await onUpgrade(oldVersion, newVersion, SqfliteSupportDatabase(db));
    }, onDowngrade: (Database db, int oldVersion, int newVersion) async {
      await onDowngrade(oldVersion, newVersion, SqfliteSupportDatabase(db));
    }, onCreate: (db, version) {}));
    return db;
  }

}

class SqfliteSupportDatabase extends SupportSQLiteDatabase {
  Database _db;
  Transaction curTransaction;

  SqfliteSupportDatabase(this._db);

  @override
  Future beginTransaction([bool exclusive = true]) {
  }

  @override
  void close() {
    _db.close();
  }

  @override
  Future<int> delete(String sql, [List<dynamic> arguments]) async {
    return await executor.rawDelete(sql, arguments);
  }

  @override
  Future endTransaction() {

  }

  @override
  Future exec(String sql, [List<dynamic> arguments]) async {
    return await executor.rawQuery(sql, arguments);
  }

  @override
  Future<int> insert(String sql, [List<dynamic> arguments]) async {
    return await executor.rawInsert(sql, arguments);
  }

  @override
  bool isOpen() {
    return _db.isOpen;
  }

  @override
  Future query(String sql, [List<dynamic> arguments]) {
    return executor.rawQuery(sql, arguments);
  }

  @override
  Future runInTransaction(FutureOr Function() block, [bool exclusive = true]) async {
    return await _db.transaction((txn) async {
      var batch = txn.batch();
      this.curTransaction = txn;
      try {
        return await block();
      } catch (e) {
        print(e);
      } finally {
         this.curTransaction = null;
      }
      await batch.commit();
    });
  }

  @override
  Future setTransactionSuccessful() {
  }

  @override
  Future<int> update(String tableName, Map<String, Object> columnMap, Map<String, Object> primaryKeyMap, [NullValueStrategy nullValueStrategy = NullValueStrategy.apply]) async {
    if (nullValueStrategy == NullValueStrategy.ignore) {
      columnMap.removeWhere((key, value) => value == null);
    }
    List<String> keys = List();
    List<dynamic> values = List();
    primaryKeyMap.forEach((key, value) {
      keys.add(key);
      values.add(value);
    });
    return await executor.update(tableName, columnMap, where: "${keys.map((key) => "$key=?").join(" and ")}", whereArgs: values.toList());
  }

  DatabaseExecutor get executor {
    return curTransaction ?? _db;
  }
}